#include "loop_queue.h"
#include <iostream>
#include <tuple>

using namespace std;

template <typename T>
LoopQueue<T>::LoopQueue(int capacity)
{
    this->cap = capacity;
    this->elements = new T *[this->cap + 1];
    this->head = 0;
    this->tail = 0;
}

template <typename T>
void LoopQueue<T>::Clear()
{
    delete this->elements;
    this->elements = new T *[this->cap + 1];
    this->head = 0;
    this->tail = 0;
}

template <typename T>
bool LoopQueue<T>::IsEmpty() const
{
    return this->head == this->tail;
}

template <typename T>
bool LoopQueue<T>::IsFull() const
{
    return (this->tail + 1) % (this->cap + 1) == this->head;
}

template <typename T>
int LoopQueue<T>::Len() const
{
    return (this->tail - this->head + this->cap + 1) % (this->cap + 1);
}

template <typename T>
bool LoopQueue<T>::EnQueue(T element)
{
    if (this->IsFull())
    {
        return false;
    }
    this->elements[this->tail] = new T(element);
    this->tail = (this->tail + 1) % (this->cap + 1);
    return true;
}

template <typename T>
tuple<bool, T> LoopQueue<T>::DeQueue()
{
    if (this->IsEmpty())
    {
        return make_tuple(false, T());
    }
    T element = *this->elements[this->head];
    delete this->elements[this->head];
    this->head = (this->head + 1) % (this->cap + 1);
    return make_tuple(true, element);
}

int main()
{
    LoopQueue<int> *q = new LoopQueue<int>(5);
    cout << "Queue Empty: " << (q->IsEmpty() ? "true" : "false") << endl;
    for (int i = 0; i < 5; i++)
    {
        bool success = q->EnQueue(i);
        cout << "Enqueued element: " << i << " Success: " << (success ? "true" : "false") << endl;
    }
    cout << "Queue Full: " << (q->IsFull() ? "true" : "false") << endl;
    for (int i = 0; i < 5; i++)
    {
        bool success;
        int element;
        tie(success, element) = q->DeQueue();
        cout << "Dequeued success: " << (success ? "true" : "false") << " element: " << element << endl;
    }
    for (int i = 0; i < 5; i++)
    {
        q->EnQueue(i);
    }
    cout << "Queue Length: " << q->Len() << endl;
    q->Clear();
    cout << "Queue Empty: " << (q->IsEmpty() ? "true" : "false") << endl;
    delete q;
    return 0;
}